#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/queue.h"
#include "driver/gpio.h"
#include "esp_log.h"
#include "esp_system.h"
#include "button_api.h"
#include "user_extern.h"

static const char *TAG = "button";
#define BUTTON_RELEASE 1
#define BUTTON_ACTIVE_LEVEL 0
#define BUTTON_SHORT_TIME 50  // 200ms
static int key_level = 0;
os_timer_t key_50ms;
static uint32_t io_num;
static xQueueHandle gpio_evt_queue = NULL;

static void gpio_isr_handler(void *arg)
{
    uint32_t gpio_num = (uint32_t)arg;
    xQueueSendFromISR(gpio_evt_queue, &gpio_num, NULL);
}

static void button_select(void)
{
    mtime.g_alarm_ring = 1;
    windows[Dsystem.windows_cur_id].Dselect(NULL);
}

static void button_enter(void)
{
   windows[Dsystem.windows_cur_id].enter(NULL);
}

static void button_exit(void)
{
    windows[Dsystem.windows_cur_id].exit(NULL);
}



void key_50ms_cb(void *args)
{
    
    os_timer_disarm(&key_50ms);
    // short timeup, check if key release
    if (BUTTON_RELEASE == gpio_get_level(io_num))
    {
        if (BUTTON_ACTIVE_LEVEL)
        {
            gpio_set_intr_type(io_num, GPIO_INTR_POSEDGE);
        }
        else
        {
            gpio_set_intr_type(io_num, GPIO_INTR_NEGEDGE);
        }

        //ESP_LOGI(TAG, "short\n");
        switch (io_num)
        {
            
            case BUTTON_SELECT:
            {
                ESP_LOGI(TAG, "select\n");
                button_select();
            }
            break;
            case BUTTON_ENTER:
            {
                ESP_LOGI(TAG, "enter\n");
                button_enter();
            }
            break;
            case BUTTON_EXIT:
            {
                ESP_LOGI(TAG, "exit\n");
                button_exit();
            }
            break;
        default:
        break;
        }
    }
    else
    {
        if (BUTTON_ACTIVE_LEVEL)
        {
            gpio_set_intr_type(io_num, GPIO_INTR_NEGEDGE);
        }
        else
        {
            gpio_set_intr_type(io_num, GPIO_INTR_POSEDGE);
        }
    }
}


static void gpio_task_example(void *arg)
{
    for(;;)
    {
        if (xQueueReceive(gpio_evt_queue, &io_num, portMAX_DELAY))
        {
            gpio_set_intr_type(io_num, GPIO_INTR_DISABLE);
            if(key_level == 0)
            {
                
                if (gpio_get_level(io_num) == BUTTON_RELEASE)
                {
                    os_timer_disarm(&key_50ms);
                    os_timer_setfn(&key_50ms, (os_timer_func_t *)key_50ms_cb, 0);
                    os_timer_arm(&key_50ms, BUTTON_SHORT_TIME, 0);
                    tone.press = 1;

                }else{
                    if(BUTTON_ACTIVE_LEVEL)
                    {
                        gpio_set_intr_type(io_num, GPIO_INTR_NEGEDGE);
                    }else{
                        gpio_set_intr_type(io_num, GPIO_INTR_POSEDGE);
                    }
                }

            }
        }
    }
}

void button_init(void)
{
    gpio_config_t io_conf;

    //config as out put mode
    io_conf.intr_type = GPIO_INTR_POSEDGE;
    io_conf.mode = GPIO_MODE_INPUT;
    io_conf.pin_bit_mask = GPIO_INPUT_PIN_SEL;
    io_conf.pull_down_en = 0;
    io_conf.pull_up_en = 1;
    gpio_config(&io_conf);

    //change gpio intrrupt type for one pin
    gpio_set_intr_type(GPIO_INPUT_IO_0, GPIO_INTR_NEGEDGE);
    gpio_set_intr_type(GPIO_INPUT_IO_1, GPIO_INTR_NEGEDGE);
    gpio_set_intr_type(GPIO_INPUT_IO_2, GPIO_INTR_NEGEDGE);
    //create a queue to handle gpio event from isr
    gpio_evt_queue = xQueueCreate(10, sizeof(uint32_t));
    //start gpio task
    xTaskCreate(gpio_task_example, "gpio_task_example", 512, NULL, 10, NULL);

    //install gpio isr service
    gpio_install_isr_service(0);

    //hook isr handler for specific gpio pin
    gpio_isr_handler_add(GPIO_INPUT_IO_0, gpio_isr_handler, (void *)GPIO_INPUT_IO_0);
    //hook isr handler for specific gpio pin
    gpio_isr_handler_add(GPIO_INPUT_IO_1, gpio_isr_handler, (void *)GPIO_INPUT_IO_1);
    //hook isr handler for specific gpio pin
    gpio_isr_handler_add(GPIO_INPUT_IO_2, gpio_isr_handler, (void *)GPIO_INPUT_IO_2);

    //netctrl_module_register_opses(g_button_control_msg_ops, USER_ARRAY_SIZE(g_button_control_msg_ops));
}